package com.yugao.fintech.antelope.pay.payment.process.payorder;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.yugao.fintech.antelope.pay.common.assembly.PayOrderAssembly;
import com.yugao.fintech.antelope.pay.common.constants.PayCacheKey;
import com.yugao.fintech.antelope.pay.common.constants.PayNodeEnum;
import com.yugao.fintech.antelope.pay.common.service.PayNodeService;
import com.yugao.fintech.antelope.pay.common.service.PayOrderService;
import com.yugao.fintech.antelope.pay.model.entity.PayNode;
import com.yugao.fintech.antelope.pay.model.entity.PayOrder;
import com.yugao.fintech.antelope.pay.model.rqrs.pay.payorder.PayOrderQO;
import com.yugao.fintech.antelope.pay.model.rqrs.pay.payorder.PayOrderRS;
import com.yugao.fintech.antelope.pay.payment.channel.AbstractPayOrderQueryService;
import com.yugao.fintech.antelope.pay.payment.channel.IPayOrderQueryService;
import com.yugao.fintech.antelope.pay.payment.model.bo.MchAppConfigContext;
import com.yugao.fintech.antelope.pay.payment.model.rqrs.ChannelRetMsgExt;
import com.yugao.fintech.antelope.pay.payment.process.ChannelPayOrderProcess;
import com.yugao.fintech.antelope.pay.payment.service.ConfigContextQueryService;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.core.response.Resp;
import com.yugao.fintech.framework.lock.manager.ILockManager;
import com.yugao.fintech.framework.lock.model.ILock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class QueryOrderProcess {
    @Autowired
    private PayOrderService payOrderService;
    @Autowired
    private ILockManager lockManager;

    @Autowired
    private ChannelPayOrderProcess channelPayOrderProcess;
    @Autowired
    private PayOrderAssembly payOrderAssembly;
    @Autowired
    private ConfigContextQueryService configContextQueryService;
    @Autowired
    private PayNodeService payNodeService;

    /**
     * 获取支付订单
     */
    @Transactional(rollbackFor = Exception.class)
    public Resp<PayOrderRS> getPayOrder(PayOrderQO rq) {
        String payOrderNo = payOrderService.getPayOrderNo(rq.getMchNo(), rq.getPayOrderNo(), rq.getMchOrderNo());
        if(StringUtils.isEmpty(payOrderNo)) {
            PayOrderRS queryPayOrderRS = new PayOrderRS();
            queryPayOrderRS.setStatus(PayOrder.STATE_NO_EXIST);
            return Resp.ok(queryPayOrderRS, "订单不存在");
        }

        ILock lock = lockManager.getLock(PayCacheKey.PAY_GLOBAL_LOCK.formatKey(payOrderNo));
        boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);
        if (!tryLock) {
            return Resp.fail("业务繁忙");
        }

        PayNode payNode = PayNode.builder().titleCode(PayNodeEnum.PAY_OK.getCode()).build();
        try {
            PayOrder payOrder = payOrderService.getMchOrder(rq.getMchNo(), rq.getPayOrderNo(), rq.getMchOrderNo());

            // 如果不是待支付和支付中状态, 则无需进一步处理直接返回即可
            if (!PayOrder.STATE_ING.equals(payOrder.getStatus()) && !PayOrder.STATE_INIT.equals(payOrder.getStatus())) {
                log.info("当前订单不处于支付中或者待支付, 无需进一步处理, payOrderNo: {}, status: {}", payOrderNo, payOrder.getStatus());
                return Resp.ok(payOrderAssembly.toPayOrderRS(payOrder));
            }

            // 如果是待支付状态, 说明没有和第三方支付平台交互-微信/支付宝/银联等(直接取消)
            if (StrUtil.equals(PayOrder.STATE_INIT, payOrder.getStatus())) {
                payOrderService.updateInit2Close(payOrder.getPayOrderNo());
                payOrder.setStatus(PayOrder.STATE_CLOSED);
                return Resp.ok(payOrderAssembly.toPayOrderRS(payOrder));
            }

            // 查询支付接口是否存在
            IPayOrderQueryService queryService = AbstractPayOrderQueryService.getService(payOrder.getIfCode());

            // 支付通道接口实现不存在
            if (queryService == null) {
                log.error("{} interface not exists!", payOrder.getIfCode());
                return Resp.fail("未实现接口代码对应的查询服务");
            }

            // 查询出商户应用的配置信息
            MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId());

            ChannelRetMsgExt channelRetMsgExt = queryService.query(payOrder, mchAppConfigContext);
            if (channelRetMsgExt == null) {
                log.error("channelRetMsg is null");
                return Resp.fail("通道返回接口为空");
            }

            log.info("获取订单并补单[{}]查询结果为：{}", payOrderNo, JSON.toJSONString(channelRetMsgExt));

            payNode.setPayOrderNo(payOrder.getPayOrderNo());

            // 查询成功
            if (channelRetMsgExt.getChannelState() == ChannelRetMsgExt.ChannelState.CONFIRM_SUCCESS) {
                if (payOrderService.updateIng2Success(payOrderNo, channelRetMsgExt)) {
                    // 订单支付成功，其他业务逻辑
                    channelPayOrderProcess.confirmSuccess(payOrder);
                }
            } else if (channelRetMsgExt.getChannelState() == ChannelRetMsgExt.ChannelState.CONFIRM_FAIL) {  //确认失败
                // 更新支付订单表为失败状态
                payOrderService.updateIng2Fail(payOrderNo, channelRetMsgExt);
                payNode.setTitleCode(PayNodeEnum.PAY_FAIL.getCode());
            } else if (channelRetMsgExt.getChannelState() == ChannelRetMsgExt.ChannelState.WAITING) {
                return Resp.ok(payOrderAssembly.toPayOrderRS(payOrder));
            }  else {
                return Resp.fail(channelRetMsgExt.getChannelErrMsg());
            }

            // 获取最新订单
            return Resp.ok(payOrderAssembly.toPayOrderRS(payOrderService.getByPayOrderNo(payOrderNo)));
        } catch (Exception e) {  //继续下一次迭代查询
            log.error("error payOrderNo = {}", payOrderNo, e);
            throw new BizException(e.getMessage());
        } finally {
            lock.unlock();
            payNodeService.savePayNode(payNode);
        }
    }
}
